package com.livestocksolutions.ui;

import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.util.ArrayList;

import javax.swing.BorderFactory;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ScrollPaneLayout;

import java.awt.BorderLayout;
import javax.swing.ScrollPaneConstants;

/* -- Version History --
 *  1.0 : 11 August 2012 - Initial version.
 *  
 *  1.1 : 23 August 2012 - Added repaint() methods to be called upon updating any of the lists.
 *  
 *  1.2 : 25 September 2012 - Added setPreferredSize(new Dimension(200,0)); to SidePanel to give it fixed width.
 */

/**
 * A scrollable area where Components can be added to the area.<p>
 * 
 * The list is separated into three parts - The top section aligns any JComponent
 * to the top of the list.<br>
 * The centre section of the SidePanel aligns its JComponents by the centre vertically.<br>
 * The bottom section of the SidePanel aligns its JComponents to the bottom of the
 * scrollable area.<br>
 * <p>
 * Example of using SidePanel<br>
 * Adding the panel to the left side of a BorderLayout
 * </p>
 * <pre style="left:10px;background:#EEE">
 * SidePanel menu = new SidePanel();
 * parent.add(menu, BorderLayout.WEST);
 * 
 * // These items are the items that appear on the top of the scrollable area
 * menu.add(SidePanel.TOP,new JButton("Main Menu Button 1"));
 * menu.add(SidePanel.TOP,new JButton("Main Menu Button 2"));
 * menu.add(SidePanel.TOP,new JButton("Main Menu 3"));
 * // Place the image into the top position in this list
 * menu.add(SidePanel.TOP,new JLabel(new ImageIcon("./img.png")),0);
 * menu.add(SidePanel.TOP,new JButton("Main Menu Button 4"));
 * 
 * // These items appear in the centre of the avaliable space
 * menu.add(SidePanel.CENTRE,new JButton("Tab Specific Button 1"));
 * menu.add(SidePanel.CENTRE,new JButton("Tab Specific Button 2"));
 * menu.add(SidePanel.CENTRE,new JButton("Tab Specific Button 3"));
 * menu.add(SidePanel.CENTRE,new JButton("Tab Specific Button 4"));
 * menu.add(SidePanel.CENTRE,new JButton("Tab Specific Button 5"));
 * 
 * // To clear the Centre section of the menu
 * menu.clearCentreMenu();
 * 
 * // To clear the whole menu
 * menu.clearMenu();
 * 
 * // Not shown is the event listeners for the JButtons to to
 * // inform the listening Objects of the button being clicked.
 * </pre>
 * 
 * @author Adam Parr
 * @author Ken DeVries
 * @version 1.2
 * @.modified 29 September 2012
 */
public class SidePanel extends JScrollPane {
	private static final long serialVersionUID = 1L;
	
	/**
	 * The top area of the Scroll area where an item can be placed
	 */
	public static final int TOP 			= 0;
	/**
	 * The centre area of the Scroll area where an item can be placed
	 */
	public static final int CENTRE		= 1;
	/**
	 * The bottom area of the Scroll area where an item can be placed
	 */
	public static final int BOTTOM 		= 2;
	
	/**
	 * The Pane that will show the JComponents at the top of the scroll area
	 */
	private JPanel topPane = new JPanel();
	
	/**
	 * The Pane that will show the JComponents at the centre of the scroll area
	 */
	private JPanel centrePane = new JPanel();
	
	/**
	 * The Pane that will show the JComponents at the bottom of the scroll area
	 */
	private JPanel bottomPane = new JPanel();
	
	/**
	 * Constraints for the menu items
	 */
	private GridBagConstraints gridConstraints = new GridBagConstraints();
	
	/**
	 * Items that are to appear in the top area of the scroll area
	 */
	private ArrayList<Component> topMenu = new ArrayList<Component>();
	
	/**
	 * Items that are to appear in the centre area of the scroll area
	 */
	private ArrayList<Component> centreMenu = new ArrayList<Component>();
	
	/**
	 * Items that are to appear in the bottom area of the scroll area
	 */
	private ArrayList<Component> bottomMenu = new ArrayList<Component>();
	
	/**
	 * A transparent colour
	 */
	private Color transparent = new Color(0,0,0,0);
	/**
	 * Constructor
	 */
	public SidePanel(){
		super();
		setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
		setBorder(BorderFactory.createEmptyBorder());
		setViewportBorder(BorderFactory.createEmptyBorder());
		getViewport().setOpaque(false);
		setOpaque(false);
		setBackground(transparent);
		setLayout(new SidePanelLayout());
		setPreferredSize(new Dimension(200,0));
		
		JPanel view = new JPanel();
		view.setOpaque(false);
		view.setBackground(transparent);
		view.setLayout(new BorderLayout(5, 5));
		
		topPane.setLayout(new GridBagLayout());
		centrePane.setLayout(new GridBagLayout());
		bottomPane.setLayout(new GridBagLayout());
		
		topPane.setOpaque(false);
		topPane.setBackground(transparent);
		centrePane.setOpaque(false);
		centrePane.setBackground(transparent);
		bottomPane.setOpaque(false);
		bottomPane.setBackground(transparent);
		
		view.add(topPane, BorderLayout.NORTH);
		view.add(centrePane, BorderLayout.CENTER);
		view.add(bottomPane, BorderLayout.SOUTH);
		
		// Default Grid Bag Constants for all items added to a GridBagLayout
		  // Allow the JComponents to fill the area
		gridConstraints.fill = GridBagConstraints.BOTH;
		  // Center the JComponents in the list
		gridConstraints.anchor = GridBagConstraints.CENTER;
		  // Add spacing to the top and bottom of each
		gridConstraints.insets = new Insets(2, 0, 2, 0);
		  // Fill the entire width
		gridConstraints.weightx = 1.0;
				
		setViewportView(view);
	}
	
	/**
	 * Clear all items in this SidePanel
	 */
	public void clearMenu(){
		clearTopMenu();
		clearCentreMenu();
		clearBottomMenu();
	}
	
	/**
	 * Clear all items in the top menu
	 */
	public void clearTopMenu(){
		topPane.removeAll();
		topMenu.clear();
		topPane.repaint();
	}
	
	/**
	 * Clear all items in the centre menu
	 */
	public void clearCentreMenu(){
		centrePane.removeAll();
		centreMenu.clear();
		centrePane.repaint();
	}
	
	/**
	 * Clear all items in the bottom menu
	 */
	public void clearBottomMenu(){
		bottomPane.removeAll();
		bottomMenu.clear();
		bottomPane.repaint();
	}
	
	/**
	 * Add this item to the list of the menu options for the menu to the centre area.
	 * @param component item to add
	 * @return The Component that was passed in.
	 */
	@Override
	public Component add(Component component){
		return add(CENTRE,component,-1);
		
	}
	
	/**
	 * Add this item to the list of the menu options for the menu to the centre area
	 * and at the given position.
	 * @param component item to add
	 * @param position the position to add this item to in the list
	 * @return The Component that was passed in.
	 */
	@Override
	public Component add(Component component, int position){
		return add(CENTRE,component,position);
		
	}
	
	/**
	 * Add this item to the list of the menu options for the menu at a particular area.
	 * @param area the area to add the JComponent to either of {@link #TOP}, {@link #CENTRE} or {@link #BOTTOM}
	 * @param component item to add
	 * @return The Component that was passed in.
	 */
	public Component add(int area,Component component){
		return add(area,component,-1);
	}
	
	/**
	 * Add this item to the list of the menu options for the menu at a particular area
	 * and at the given position.
	 * @param area the area to add the JComponent to either of {@link #TOP}, {@link #CENTRE} or {@link #BOTTOM}
	 * @param component item to add
	 * @param position the position to add this item to in the list
	 * @return The Component that was passed in.
	 */
	public Component add(int area,Component component, int position){
		switch(area){
			case TOP:
				topMenu.add(position<0?topMenu.size():position, component);
				redrawTopMenu();
				break;
			case BOTTOM:
				bottomMenu.add(position<0?bottomMenu.size():position, component);
				redrawBottomMenu();
				break;
			case CENTRE:
			default:
				centreMenu.add(position<0?centreMenu.size():position, component);
				redrawCentreMenu();
		}
		validate();
		return component;
	}
	
	/**
	 * Redraw the top menu section of this SidePanel
	 */
	private void redrawTopMenu(){
		topPane.removeAll();
		for(int x=0; x<topMenu.size(); x++){
			gridConstraints.gridy = x;
			topPane.add(topMenu.get(x),gridConstraints);
		}
		topPane.validate();
	}
	
	/**
	 * Redraw the centre menu section of this SidePanel
	 */
	private void redrawCentreMenu(){
		centrePane.removeAll();
		for(int x=0; x<centreMenu.size(); x++){
			gridConstraints.gridy = x;
			centrePane.add(centreMenu.get(x),gridConstraints);
		}
		centrePane.validate();
	}
	
	/**
	 * Redraw the bottom menu section of this SidePanel
	 */
	private void redrawBottomMenu(){
		bottomPane.removeAll();
		for(int x=0; x<bottomMenu.size(); x++){
			gridConstraints.gridy = x;
			bottomPane.add(bottomMenu.get(x),gridConstraints);
		}
		bottomPane.validate();
	}

	
	/* -- Version History --
	 *  1.0 : 11 August 2012 - Initial version.
	 */

	/**
	 * An Private Class to create a desirable layout when the height is greater than
	 * the height of the window whereby a vertical scrollbar becomes visible, obscuring
	 * portions of the items in the list.
	 * @author Adam Parr
	 * @version 1.0
	 * @.modified 11 August 2012
	 */
	private static class SidePanelLayout extends ScrollPaneLayout {
		private static final long serialVersionUID = 1L;

		@Override
		public Dimension preferredLayoutSize(Container parent) {
			Dimension dim =  super.preferredLayoutSize(parent);
			JScrollPane pane = (JScrollPane) parent;
			if (pane.getViewport().getExtentSize().height < pane.getViewport().getView().getPreferredSize().height) {
				dim.width += pane.getVerticalScrollBar().getPreferredSize().width;
			}
			return dim;
		}
	}
}